home *** CD-ROM | disk | FTP | other *** search
/ Workbench Add-On / Workbench Add-On - Volume 1.iso / BBS-Archive / Comm / AmiTCP30b2.lha / src / rpclib / svc_tcp.c < prev    next >
C/C++ Source or Header  |  1994-03-09  |  11KB  |  433 lines

  1. /*
  2.  * $Id: svc_tcp.c,v 1.2 1993/11/14 16:32:04 jraja Exp $
  3.  *
  4.  * $Log: svc_tcp.c,v $
  5.  * Revision 1.2  1993/11/14  16:32:04  jraja
  6.  * Fixed include. ANSI prototypes. Fixed types.
  7.  * AMITCP: ioctl() to IoctlSocket(), close() to CloseSocket(),
  8.  *         read() to recv(), write() to send().
  9.  * AMITCP: cancelled EINTR handling.
  10.  * AMITCP: cancelled svcfd_create(), since recv() cannot be done on file fd.
  11.  *
  12.  */
  13. /* @(#)svc_tcp.c    2.2 88/08/01 4.0 RPCSRC */
  14. /*
  15.  * Sun RPC is a product of Sun Microsystems, Inc. and is provided for
  16.  * unrestricted use provided that this legend is included on all tape
  17.  * media and as a part of the software program in whole or part.  Users
  18.  * may copy or modify Sun RPC without charge, but are not authorized
  19.  * to license or distribute it to anyone else except as part of a product or
  20.  * program developed by the user.
  21.  * 
  22.  * SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE
  23.  * WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR
  24.  * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE.
  25.  * 
  26.  * Sun RPC is provided with no support and without any obligation on the
  27.  * part of Sun Microsystems, Inc. to assist in its use, correction,
  28.  * modification or enhancement.
  29.  * 
  30.  * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE
  31.  * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY SUN RPC
  32.  * OR ANY PART THEREOF.
  33.  * 
  34.  * In no event will Sun Microsystems, Inc. be liable for any lost revenue
  35.  * or profits or other special, indirect and consequential damages, even if
  36.  * Sun has been advised of the possibility of such damages.
  37.  * 
  38.  * Sun Microsystems, Inc.
  39.  * 2550 Garcia Avenue
  40.  * Mountain View, California  94043
  41.  */
  42. #if !defined(lint) && defined(SCCSIDS)
  43. static char sccsid[] = "@(#)svc_tcp.c 1.21 87/08/11 Copyr 1984 Sun Micro";
  44. #endif
  45.  
  46. /*
  47.  * svc_tcp.c, Server side for TCP/IP based RPC. 
  48.  *
  49.  * Copyright (C) 1984, Sun Microsystems, Inc.
  50.  *
  51.  * Actually implements two flavors of transporter -
  52.  * a tcp rendezvouser (a listner and connection establisher)
  53.  * and a record/tcp stream.
  54.  */
  55.  
  56. #include <sys/param.h>
  57. #include <stdio.h>
  58. #include <stdlib.h>
  59. #include <rpc/rpc.h>
  60. #include <sys/socket.h>
  61. #include <errno.h>
  62.  
  63. /*
  64.  * Ops vector for TCP/IP based rpc service handle
  65.  */
  66. static bool_t        svctcp_recv(SVCXPRT *xprt, struct rpc_msg *msg);
  67. static enum xprt_stat    svctcp_stat(SVCXPRT *xprt);
  68. static bool_t        svctcp_getargs(SVCXPRT *xprt, xdrproc_t xdr_args,
  69.                        void *args_ptr);
  70. static bool_t        svctcp_reply(SVCXPRT *xprt, struct rpc_msg *msg);
  71. static bool_t        svctcp_freeargs(SVCXPRT *xprt, xdrproc_t xdr_args,
  72.                     void *args_ptr);
  73. static void        svctcp_destroy(SVCXPRT *xprt);
  74.  
  75. static struct xp_ops svctcp_op = {
  76.     svctcp_recv,
  77.     svctcp_stat,
  78.     svctcp_getargs,
  79.     svctcp_reply,
  80.     svctcp_freeargs,
  81.     svctcp_destroy
  82. };
  83.  
  84. /*
  85.  * Ops vector for TCP/IP rendezvous handler
  86.  */
  87. static bool_t        rendezvous_request(SVCXPRT *xprt, 
  88.                        struct rpc_msg *notused);
  89. static enum xprt_stat    rendezvous_stat(SVCXPRT *xprt);
  90.  
  91. static struct xp_ops svctcp_rendezvous_op = {
  92.     rendezvous_request,
  93.     rendezvous_stat,
  94.     (int(*)(SVCXPRT *, xdrproc_t, void *))abort,
  95.     (int(*)(SVCXPRT *, struct rpc_msg *))abort,
  96.     (int(*)(SVCXPRT *, xdrproc_t, void *))abort,
  97.     svctcp_destroy
  98. };
  99.  
  100. static int readtcp(SVCXPRT *xprt, caddr_t buf, int len), 
  101.   writetcp(SVCXPRT *xprt, caddr_t buf, int len);
  102. static SVCXPRT *makefd_xprt(int fd, u_int sendsize, u_int recvsize);
  103.  
  104. struct tcp_rendezvous { /* kept in xprt->xp_p1 */
  105.     u_int sendsize;
  106.     u_int recvsize;
  107. };
  108.  
  109. struct tcp_conn {  /* kept in xprt->xp_p1 */
  110.     enum xprt_stat strm_stat;
  111.     u_long x_id;
  112.     XDR xdrs;
  113.     char verf_body[MAX_AUTH_BYTES];
  114. };
  115.  
  116. /*
  117.  * Usage:
  118.  *    xprt = svctcp_create(sock, send_buf_size, recv_buf_size);
  119.  *
  120.  * Creates, registers, and returns a (rpc) tcp based transporter.
  121.  * Once *xprt is initialized, it is registered as a transporter
  122.  * see (svc.h, xprt_register).  This routine returns
  123.  * a NULL if a problem occurred.
  124.  *
  125.  * If sock<0 then a socket is created, else sock is used.
  126.  * If the socket, sock is not bound to a port then svctcp_create
  127.  * binds it to an arbitrary port.  The routine then starts a tcp
  128.  * listener on the socket's associated port.  In any (successful) case,
  129.  * xprt->xp_sock is the registered socket number and xprt->xp_port is the
  130.  * associated port number.
  131.  *
  132.  * Since tcp streams do buffered io similar to stdio, the caller can specify
  133.  * how big the send and receive buffers are via the second and third parms;
  134.  * 0 => use the system default.
  135.  */
  136. SVCXPRT *
  137. svctcp_create(sock, sendsize, recvsize)
  138.     register int sock;
  139.     u_int sendsize;
  140.     u_int recvsize;
  141. {
  142.     bool_t madesock = FALSE;
  143.     register SVCXPRT *xprt;
  144.     register struct tcp_rendezvous *r;
  145.     struct sockaddr_in addr;
  146. #ifdef AMITCP
  147.     long len = sizeof(struct sockaddr_in);
  148. #else
  149.     int len = sizeof(struct sockaddr_in);
  150. #endif
  151.     if (sock == RPC_ANYSOCK) {
  152.         if ((sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)) < 0) {
  153.             perror("svctcp_.c - udp socket creation problem");
  154.             return ((SVCXPRT *)NULL);
  155.         }
  156.         madesock = TRUE;
  157.     }
  158.     bzero((char *)&addr, sizeof (addr));
  159.     addr.sin_family = AF_INET;
  160.     if (bindresvport(sock, &addr)) {
  161.         addr.sin_port = 0;
  162.         (void)bind(sock, (struct sockaddr *)&addr, len);
  163.     }
  164.     if ((getsockname(sock, (struct sockaddr *)&addr, &len) != 0)  ||
  165.         (listen(sock, 2) != 0)) {
  166.         perror("svctcp_.c - cannot getsockname or listen");
  167.         if (madesock)
  168. #ifdef AMITCP
  169.                (void)CloseSocket(sock);
  170. #else
  171.                (void)close(sock);
  172. #endif
  173.         return ((SVCXPRT *)NULL);
  174.     }
  175.     r = (struct tcp_rendezvous *)mem_alloc(sizeof(*r));
  176.     if (r == NULL) {
  177.         (void) fprintf(stderr, "svctcp_create: out of memory\n");
  178.         return (NULL);
  179.     }
  180.     r->sendsize = sendsize;
  181.     r->recvsize = recvsize;
  182.     xprt = (SVCXPRT *)mem_alloc(sizeof(SVCXPRT));
  183.     if (xprt == NULL) {
  184.         (void) fprintf(stderr, "svctcp_create: out of memory\n");
  185.         return (NULL);
  186.     }
  187.     xprt->xp_p2 = NULL;
  188.     xprt->xp_p1 = (caddr_t)r;
  189.     xprt->xp_verf = _null_auth;
  190.     xprt->xp_ops = &svctcp_rendezvous_op;
  191.     xprt->xp_port = ntohs(addr.sin_port);
  192.     xprt->xp_sock = sock;
  193.     xprt_register(xprt);
  194.     return (xprt);
  195. }
  196.  
  197. #ifndef AMITCP
  198. /*
  199.  * Like svctcp_create(), except the routine takes any *open* UNIX file
  200.  * descriptor as its first input.
  201.  */
  202. SVCXPRT *
  203. svcfd_create(fd, sendsize, recvsize)
  204.     int fd;
  205.     u_int sendsize;
  206.     u_int recvsize;
  207. {
  208.  
  209.     return (makefd_xprt(fd, sendsize, recvsize));
  210. }
  211. #endif
  212.  
  213. static SVCXPRT *
  214. makefd_xprt(int fd, u_int sendsize, u_int recvsize)
  215. {
  216.     register SVCXPRT *xprt;
  217.     register struct tcp_conn *cd;
  218.  
  219.     xprt = (SVCXPRT *)mem_alloc(sizeof(SVCXPRT));
  220.     if (xprt == (SVCXPRT *)NULL) {
  221.         (void) fprintf(stderr, "svc_tcp: makefd_xprt: out of memory\n");
  222.         goto done;
  223.     }
  224.     cd = (struct tcp_conn *)mem_alloc(sizeof(struct tcp_conn));
  225.     if (cd == (struct tcp_conn *)NULL) {
  226.         (void) fprintf(stderr, "svc_tcp: makefd_xprt: out of memory\n");
  227.         mem_free((char *) xprt, sizeof(SVCXPRT));
  228.         xprt = (SVCXPRT *)NULL;
  229.         goto done;
  230.     }
  231.     cd->strm_stat = XPRT_IDLE;
  232.     xdrrec_create(&(cd->xdrs), sendsize, recvsize,
  233.         xprt, readtcp, writetcp);
  234.     xprt->xp_p2 = NULL;
  235.     xprt->xp_p1 = (caddr_t)cd;
  236.     xprt->xp_verf.oa_base = cd->verf_body;
  237.     xprt->xp_addrlen = 0;
  238.     xprt->xp_ops = &svctcp_op;  /* truely deals with calls */
  239.     xprt->xp_port = 0;  /* this is a connection, not a rendezvouser */
  240.     xprt->xp_sock = fd;
  241.     xprt_register(xprt);
  242.     done:
  243.     return (xprt);
  244. }
  245.  
  246. static bool_t
  247. rendezvous_request(register SVCXPRT *xprt, struct rpc_msg *notused)
  248. {
  249.     int sock;
  250.     struct tcp_rendezvous *r;
  251.     struct sockaddr_in addr;
  252. #ifdef AMITCP
  253.     long len;
  254. #else
  255.     int len;
  256. #endif
  257.  
  258.     r = (struct tcp_rendezvous *)xprt->xp_p1;
  259.     again:
  260.     len = sizeof(struct sockaddr_in);
  261.     if ((sock = accept(xprt->xp_sock, (struct sockaddr *)&addr,
  262.         &len)) < 0) {
  263. #ifndef AMITCP /* EINTR is returned in case of a CTRL-C by default */
  264.         if (errno == EINTR)
  265.             goto again;
  266. #endif
  267.            return (FALSE);
  268.     }
  269.     /*
  270.      * make a new transporter (re-uses xprt)
  271.      */
  272.     xprt = makefd_xprt(sock, r->sendsize, r->recvsize);
  273.     xprt->xp_raddr = addr;
  274.     xprt->xp_addrlen = len;
  275.     return (FALSE); /* there is never an rpc msg to be processed */
  276. }
  277.  
  278. static enum xprt_stat
  279. rendezvous_stat(SVCXPRT *xprt)
  280. {
  281.     return (XPRT_IDLE);
  282. }
  283.  
  284. static void
  285. svctcp_destroy(register SVCXPRT *xprt)
  286. {
  287.     register struct tcp_conn *cd = (struct tcp_conn *)xprt->xp_p1;
  288.  
  289.     xprt_unregister(xprt);
  290. #ifdef AMITCP
  291.     (void)CloseSocket(xprt->xp_sock);
  292. #else
  293.     (void)close(xprt->xp_sock);
  294. #endif
  295.     if (xprt->xp_port != 0) {
  296.         /* a rendezvouser socket */
  297.         xprt->xp_port = 0;
  298.     } else {
  299.         /* an actual connection socket */
  300.         XDR_DESTROY(&(cd->xdrs));
  301.     }
  302.     mem_free((caddr_t)cd, sizeof(struct tcp_conn));
  303.     mem_free((caddr_t)xprt, sizeof(SVCXPRT));
  304. }
  305.  
  306. /*
  307.  * All read operations timeout after 35 seconds.
  308.  * A timeout is fatal for the connection.
  309.  */
  310. static struct timeval wait_per_try = { 35, 0 };
  311.  
  312. /*
  313.  * reads data from the tcp conection.
  314.  * any error is fatal and the connection is closed.
  315.  * (And a read of zero bytes is a half closed stream => error.)
  316.  */
  317. static int
  318. readtcp(register SVCXPRT *xprt, caddr_t buf, register int len)
  319. {
  320.     register int sock = xprt->xp_sock;
  321. #ifdef FD_SETSIZE
  322.     fd_set mask;
  323.     fd_set readfds;
  324.  
  325.     FD_ZERO(&mask);
  326.     FD_SET(sock, &mask);
  327. #else
  328.     register int mask = 1 << sock;
  329.     int readfds;
  330. #endif /* def FD_SETSIZE */
  331.     do {
  332.         readfds = mask;
  333.         if (select(_rpc_dtablesize(), &readfds, NULL,
  334.                NULL, &wait_per_try) <= 0) {
  335. #ifndef AMITCP /* EINTR is returned in case of a CTRL-C by default */
  336.             if (errno == EINTR) {
  337.                 continue;
  338.             }
  339. #endif
  340.             goto fatal_err;
  341.         }
  342. #ifdef FD_SETSIZE
  343.     } while (!FD_ISSET(sock, &readfds));
  344. #else
  345.     } while (readfds != mask);
  346. #endif /* def FD_SETSIZE */
  347.     if ((len = recv(sock, buf, len, 0)) > 0) {
  348.         return (len);
  349.     }
  350. fatal_err:
  351.     ((struct tcp_conn *)(xprt->xp_p1))->strm_stat = XPRT_DIED;
  352.     return (-1);
  353. }
  354.  
  355. /*
  356.  * writes data to the tcp connection.
  357.  * Any error is fatal and the connection is closed.
  358.  */
  359. static int
  360. writetcp(register SVCXPRT *xprt, caddr_t buf, int len)
  361. {
  362.     register int i, cnt;
  363.  
  364.     for (cnt = len; cnt > 0; cnt -= i, buf += i) {
  365.         if ((i = send(xprt->xp_sock, buf, cnt, 0)) < 0) {
  366.             ((struct tcp_conn *)(xprt->xp_p1))->strm_stat =
  367.                 XPRT_DIED;
  368.             return (-1);
  369.         }
  370.     }
  371.     return (len);
  372. }
  373.  
  374. static enum xprt_stat
  375. svctcp_stat(SVCXPRT *xprt)
  376. {
  377.     register struct tcp_conn *cd =
  378.         (struct tcp_conn *)(xprt->xp_p1);
  379.  
  380.     if (cd->strm_stat == XPRT_DIED)
  381.         return (XPRT_DIED);
  382.     if (! xdrrec_eof(&(cd->xdrs)))
  383.         return (XPRT_MOREREQS);
  384.     return (XPRT_IDLE);
  385. }
  386.  
  387. static bool_t
  388. svctcp_recv(SVCXPRT *xprt, register struct rpc_msg *msg)
  389. {
  390.     register struct tcp_conn *cd =
  391.         (struct tcp_conn *)(xprt->xp_p1);
  392.     register XDR *xdrs = &(cd->xdrs);
  393.  
  394.     xdrs->x_op = XDR_DECODE;
  395.     (void)xdrrec_skiprecord(xdrs);
  396.     if (xdr_callmsg(xdrs, msg)) {
  397.         cd->x_id = msg->rm_xid;
  398.         return (TRUE);
  399.     }
  400.     return (FALSE);
  401. }
  402.  
  403. static bool_t
  404. svctcp_getargs(SVCXPRT *xprt, xdrproc_t xdr_args, void *args_ptr)
  405. {
  406.     return ((*xdr_args)(&(((struct tcp_conn *)(xprt->xp_p1))->xdrs), args_ptr));
  407. }
  408.  
  409. static bool_t
  410. svctcp_freeargs(SVCXPRT *xprt, xdrproc_t xdr_args, void *args_ptr)
  411. {
  412.     register XDR *xdrs =
  413.         &(((struct tcp_conn *)(xprt->xp_p1))->xdrs);
  414.  
  415.     xdrs->x_op = XDR_FREE;
  416.     return ((*xdr_args)(xdrs, args_ptr));
  417. }
  418.  
  419. static bool_t
  420. svctcp_reply(SVCXPRT *xprt, register struct rpc_msg *msg)
  421. {
  422.     register struct tcp_conn *cd =
  423.         (struct tcp_conn *)(xprt->xp_p1);
  424.     register XDR *xdrs = &(cd->xdrs);
  425.     register bool_t stat;
  426.  
  427.     xdrs->x_op = XDR_ENCODE;
  428.     msg->rm_xid = cd->x_id;
  429.     stat = xdr_replymsg(xdrs, msg);
  430.     (void)xdrrec_endofrecord(xdrs, TRUE);
  431.     return (stat);
  432. }
  433.